package com.ffpc.sql;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.Date;

/**
 * A wrapper for Connection objects to support connection pooling. All methods
 * specified by the Connection interface except close() are delegated to the
 * underlying Connection object.
 * 
 * @author KENNETHLCH
 * @version $Id: PooledConnection.java,v 1.1.1.1 2013/08/16 05:35:48 tengyang Exp $
 */
public class PooledConnection extends ConnectionWrapper {

    private ConnectionPool pool;
    private boolean leased;
    private long leasedSince;
    private String stackTrace;
    private ConnectionFactory factory;
    
    PooledConnection(Connection cxn, ConnectionPool pool) {
        super(cxn);
        this.pool = pool;
    }

    void setConnectionFactory(ConnectionFactory factory) {
        this.factory = factory;
    }
    
    void markLeased() {
        leased = true;
        leasedSince = System.currentTimeMillis();
        
        StringWriter sw = new StringWriter();
        new Exception().fillInStackTrace().printStackTrace(new PrintWriter(sw, true));
        stackTrace = sw.toString();
    }
    
    public boolean isLeased() {
        return leased;
    }
    
    public long getLeasedSince() {
        return leasedSince;
    }
    
    public long getLeasedTime() {
        return System.currentTimeMillis() - leasedSince;
    }
    
    String getStackTrace() {
        return stackTrace;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer(super.toString() + "[");
        
        sb.append("cxn=" + getWrapped().toString());
        
        if (isLeased()) {
            sb.append(", leasedSince=" + new Date(leasedSince));
            sb.append(", leasedTime(mins)=" + new DecimalFormat("#,##0.00").format(getLeasedTime() / 60000.0));
        }
        
        return sb.append("]").toString();
    }

    @Override
    protected void finalize() throws Throwable {
        close();
    }

    /**
     * Actually close the underlying Connection.
     * 
     * @throws SQLException
     */
    void hardClose() throws SQLException {
        getWrapped().close();
    }

    /**
     * Returns the underlying Connection to the pool.
     * 
     * @throws SQLException
     */
    @Override
    public void close() throws SQLException {
        if (leased) {
            pool.release(this);
            leased = false;
            // breaks the circular reference with factory
            if (factory != null)
                factory.setConnection(null);
            factory = null;
        }
    }

}
